package com.adee.java.nio;

import lombok.SneakyThrows;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class SelectorClientTest2 {
    public static void main(String[] args) throws IOException, InterruptedException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 8);
        socketChannel.configureBlocking(false);
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 9000);
        // 如果SocketChannel处于非阻塞模式并且你调用了connect()方法的话，该方法会在一个链接建立之前就返回。
        // 你可以调用finishConnect()方法去判断一个链接有没有建立
        if(!socketChannel.connect(address)) { // 连接未成功，立即返回
            while (!socketChannel.finishConnect()) { // 循环检查连接是否完成
                System.out.println("连接尚未完成...");
                Thread.sleep(10);
            }
        }

        Selector selector = Selector.open();

        socketChannel.register(selector, SelectionKey.OP_WRITE);
        socketChannel.register(selector, SelectionKey.OP_READ);

        // 连接成功，发送数据
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNextLine()) {
            String str = scanner.nextLine();
            byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
            new Thread(new IOHandler(selector, socketChannel, bytes)).start();
        }

    }

    public static class IOHandler implements Runnable {
        private Selector selector;
        private SocketChannel socketChannel;
        private byte[] bytes;

        public IOHandler(Selector selector, SocketChannel socketChannel, byte[] bytes) {
            this.selector = selector;
            this.socketChannel = socketChannel;
            this.bytes = bytes;
        }

        @SneakyThrows
        @Override
        public void run() {
            ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
            buffer.put(bytes); // 写buffer
            buffer.flip();
            int receiveBufferSize = socketChannel.socket().getReceiveBufferSize();
            int sendBufferSize = socketChannel.socket().getSendBufferSize();
            System.out.printf("receiveBufferSize: %d\n", receiveBufferSize);
            System.out.printf("sendBufferSize: %d\n", sendBufferSize);
            System.out.printf("buffer可发送字节数：%d\n", buffer.limit()-buffer.position());

//            ByteBuffer mBuffer = ByteBuffer.wrap(megaBytes(10, (byte) 121, true));
            String str = "针对后者，TCP协议实现了一个算法——Nagle，它通过将发送缓冲区内的小的报文段自动相连";
            ByteBuffer mBuffer = ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8));
            while (mBuffer.hasRemaining()) { // 没发送完继续发送
                int writeBytes = socketChannel.write(mBuffer);
                System.out.println("写出字节数：" + writeBytes);
            }


            receiveBufferSize = socketChannel.socket().getReceiveBufferSize();
            sendBufferSize = socketChannel.socket().getSendBufferSize();
            System.out.printf("receiveBufferSize: %d\n", receiveBufferSize);
            System.out.printf("sendBufferSize: %d\n", sendBufferSize);

            while (true) {
                int cnt = selector.select();
                if (cnt < 1) continue;
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    if (key.isReadable()) {
                        System.out.println("读事件：");
                        SocketChannel sc = (SocketChannel)key.channel();
                        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                        int readCount = sc.read(readBuffer);
                        readBuffer.flip();
                        byte[] readBytes = new byte[readCount];
                        readBuffer.get(readBytes);
                        System.out.println(new String(readBytes));
                    } else if(key.isWritable()) {
                        System.out.println("写事件：");

                    }
                }

            }
        }
    }

    // 创建一个n兆大小的字节数组，初始化字节为b，是否自定义初始化字节
    private static byte[] megaBytes(int n, byte b, boolean init) {
        byte[] k = new byte[1024];
        if(init) { // 初始化为指定字节b
            for (int i = 0; i < k.length; i++) {
                k[i] = b;
            }
        }
        byte[] m = new byte[1024*1024];
        for (int i = 0; i < 1024; i++) {
            System.arraycopy(k, 0, m, i*1024, 1024);
        }
        byte[] ret = new byte[n*1024*1024];
        for (int i = 0; i < n; i++) {
            System.arraycopy(m, 0, ret, i*1024*1024, 1024*1024);
        }
        return ret;
    }
}
